#include "VAutoWrapper.h"
#include "UISpeechManager.h"
#include "UIJSONParser.h"
#include "UISpeechEvent.h"
#include <iostream>
#include <ctime>

UISpeechManager::UISpeechManager(void)
  : UIModule(MODULE_SpeechManager) 
{
	std::string ttsEngineDef = "";
	m_pConfigurator->getStringValue(MODULE_SpeechManager, "tts", "engine.tts", ttsEngineDef);
	switch (getTTSEngineType(ttsEngineDef)) 
	{
	case TTS_ENGINE_VAUTO:
		m_ttsEngine = new VAutoWrapper();
		break;
	default:
		m_pLogger->err(MODULE_SpeechManager, "UISpeechManager", "No valid TTS engine defined.");
		m_ttsEngine = NULL;
	}
	if (m_ttsEngine) {
		if (!m_ttsEngine->initialize()) {
			m_pLogger->err(MODULE_SpeechManager, "UISpeechManager", "TTS Engine initialization failed.");
			m_ttsEngine = NULL;
		}
	}

	m_hybridSR = new HybridSpeechRecognizer();

	std::string domain = "UnknownDomain";
	std::string siteID = "UnknwonSite";
	m_pConfigurator->getStringValue(MODULE_SpeechManager, "sr-logging", "domain", domain);
	m_pConfigurator->getStringValue(MODULE_SpeechManager, "sr-logging", "siteID", siteID);

	time_t t = time(NULL);
	tm* pTime = localtime(&t);

	char timetag[1024];
	sprintf(timetag, "%4d-%02d-%02d-%02d-%02d", 
		pTime->tm_year + 1900,
		pTime->tm_mon + 1,
		pTime->tm_mday,
		pTime->tm_hour,
		pTime->tm_min);

	m_speechLogPrefix = m_pLogger->getSpeechLogPath();
	m_speechLogPrefix = m_speechLogPrefix + "\\" + domain + "-" + siteID + "-" + timetag + "-utt";
	m_speechLogID = 1;

	m_ttsLogPrefix = m_pLogger->getTTSLogPath();
	m_ttsLogPrefix = m_ttsLogPrefix + "\\" + domain + "-" + siteID + "-" + timetag + "-tts";
	m_ttsLogID = 1;
}

UISpeechManager::~UISpeechManager(void)
{
	if (m_hybridSR)
		delete m_hybridSR;
	if (m_ttsEngine)
		delete m_ttsEngine;
}

// virtual
bool UISpeechManager::processSyncEvent(UIEvent* event)
{
	if (equalsIgnoreCase(event->getType(), EVENT_IN_START_RECORDING)) {
		m_hybridSR->recFromMic(event->getSessionID(), getSpeechLogFile(event->getSessionID()));
	}
	
	if (equalsIgnoreCase(event->getType(), EVENT_IN_STOP_RECORDING)) {
		m_hybridSR->stopRecording(event->getSessionID());
	}
	
	if (equalsIgnoreCase(event->getType(), EVENT_IN_USER_VOICE_DATA)) {
		std::string filename;
		if (UIJSONParser::getString(event->getValue(), "file", filename)) {
			m_hybridSR->recFromFile(event->getSessionID(), filename.c_str());
		}
		//TODO: implement recieving and process data
	}

	if (equalsIgnoreCase(event->getType(), EVENT_IN_BATCH_SR_TEST)) {
		std::string hrlName;
		if (UIJSONParser::getString(event->getValue(), "hrl", hrlName)) {
			SRNLUBatchTester* pTester = SRNLUBatchTester::getInstance();
			pTester->setTestMode(SR_NLU_BATCH_SR);
			pTester->init(hrlName);
			SRNLUReference ref;
			int iTestCase = 1;
			while (pTester->getNextTestCase(ref)) {
				m_hybridSR->test(ref);
				std::cout << toStr(iTestCase++) << ": End SR " << ref.audioSource << std::endl;
			}
		}
	}

	if (equalsIgnoreCase(event->getType(), EVENT_IN_BATCH_SR_NLU_TEST)) {
		std::string hrlName;
		if (UIJSONParser::getString(event->getValue(), "hrl", hrlName)) {
			SRNLUBatchTester* pTester = SRNLUBatchTester::getInstance();
			pTester->setTestMode(SR_NLU_BATCH_SR_NLU);
			pTester->init(hrlName);
			SRNLUReference ref;
			int iTestCase = 1;
			while (pTester->getNextTestCase(ref)) {
				m_hybridSR->test(ref);
				std::cout << toStr(iTestCase++) << ": End SR " << ref.audioSource << std::endl;
			}
		}
	}

	if (equalsIgnoreCase(event->getType(), EVENT_IN_CONTEXT_UPDATE)) {
		std::vector<std::string> strKeyValuePairs;
		std::string eventStr = event->getValue();
		splitString(&eventStr, "=", &strKeyValuePairs);
		m_hybridSR->updateContext(strKeyValuePairs[0], strKeyValuePairs[1]);
	}

	if (equalsIgnoreCase(event->getType(), EVENT_IN_TTS_TEXT)) {
		std::string text;
		if (!m_ttsEngine)
			sendSpeechOutboundEvent(event->getSessionID(), -1, EVENT_OUT_SR_NLU_RESULT, serializeTTSError(TTS_ERROR_ENGINE_NOT_START));
		if (m_ttsEngine && UIJSONParser::getString(event->getValue(), "text", text)) {
			if (m_ttsEngine->getType() == TTS_ENGINE_VAUTO) {
				text = replaceAll(text, "pause=", "\\pause=");
				text = replaceAll(text, "=endpause", "\\");
			}
			m_ttsEngine->speak(event->getSessionID(), text.c_str(), getTTSLogFile(event->getSessionID()).c_str());
		}
	}

	if (equalsIgnoreCase(event->getType(), EVENT_IN_TTS_STOP)) {
		if (m_ttsEngine)
			m_ttsEngine->stop();
	}

	if (equalsIgnoreCase(event->getType(), EVENT_IN_PARAMETER_UPDATE)) {
		//TODO: implement parameter update
	}
	return true;
}

//virtual
bool UISpeechManager::processAsyncEvent(UIEvent* event)
{
#ifdef _DEBUG
	std::cout << "SpeechManager: process async event" << std::endl << event->serializeJson() << std::endl;
#endif
	return true;
}

bool UISpeechManager::processData(UIEvent* event)
{
	std::cout << "Speech: Data Event Received! (length=" << event->getDataLength() << ")" << std::endl;
	return true;
}

//virtual
bool UISpeechManager::cancel(void) 
{
#ifdef _DEBUG
	std::cout << "SpeechManager: cancel" << std::endl;
#endif
	m_hybridSR->cancel();
	return true;
}

std::string UISpeechManager::getSpeechLogFile(int sessionID)
{
	char filename[4096];
	if (sessionID == -1)
		sprintf(filename, "%sUNKT-%03d.wav", m_speechLogPrefix.c_str(), m_speechLogID++);
	else 
		sprintf(filename, "%s%03d.wav", m_speechLogPrefix.c_str(), sessionID);
	return std::string(filename);
}

std::string UISpeechManager::getTTSLogFile(int sessionID)
{
	char filename[4096];
	if (sessionID == -1)
		sprintf(filename, "%sUNKT-%03d.wav", m_ttsLogPrefix.c_str(), m_ttsLogID++);
	else
		sprintf(filename, "%s%03d.wav", m_ttsLogPrefix.c_str(), sessionID);
	return std::string(filename);
}
